package com.morty.jwt;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.UUID;

/**
 * @Author:
 * @Date:
 * @Description: jwt操作工具
 */
public class JwtUtil {

	//密钥 -- 根据实际项目，这里可以做成配置
	public static final String KEY = "%9O!y*t%8I82szOs";

	/**
	 * 由字符串生成加密key
	 * @return
	 */
	public static SecretKey generalKey(){
		byte[] encodedKey = Base64.decodeBase64(KEY);
		SecretKeySpec key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");

		return key;
	}

	/**
	 * 创建jwt
	 * @return
	 * @throws Exception
	 */
	public static String createJWT(String subject) throws Exception {

		// 指定签名的时候使用的签名算法，也就是header那部分，jjwt已经将这部分内容封装好了。
		SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

		// 生成JWT的时间
		long nowMillis = System.currentTimeMillis();
		//过期时间
		Long expires_in = nowMillis+(1000 * 60 * 60L);

		// 下面就是在为payload添加各种标准声明和私有声明了
		JwtBuilder builder = Jwts.builder()
				// 设置jti(JWT ID)：是JWT的唯一标识，根据业务需要，这个可以设置为一个不重复的值，主要用来作为一次性token,从而回避重放攻击。
				.setId(UUID.randomUUID().toString())
				// iat: jwt的签发时间
				.setIssuedAt(new Date(nowMillis))
				// issuer：jwt签发人
				.setIssuer("morty")
				//过期时间
				.setExpiration(new Date(expires_in))
				// sub(Subject)：代表这个JWT的主体，即它的所有人，这个是一个json格式的字符串，可以存放什么userid，roleid之类的，作为什么用户的唯一标志。
				.setSubject(subject)
				// 设置签名使用的签名算法和签名使用的秘钥
				.signWith(signatureAlgorithm, generalKey());
		return builder.compact();
	}

	/**
	 * 解密jwt
	 * @param jwt
	 * @return
	 * @throws Exception
	 */
	public static Claims parseJWT(String jwt) throws Exception {
		//签名秘钥，和生成的签名的秘钥一模一样
		SecretKey key = generalKey();
		//得到DefaultJwtParser
		Claims claims = Jwts.parser()
				//设置签名的秘钥
				.setSigningKey(key)
				//设置需要解析的jwt
				.parseClaimsJws(jwt).getBody();
		return claims;
	}

	/**
	 * 验证jwt
	 * @param jwt
	 * @return
	 */
	public static boolean checkJWT(String jwt) {
		try {
			Claims body = Jwts.parser().setSigningKey(generalKey()).parseClaimsJws(jwt).getBody();
			if (body != null) {
				return true;
			}
		} catch (Exception e) {
			return false;
		}
		return false;
	}
}
